// Copyright 2025 The Pigweed Authors
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.

#include "pw_crypto/ecdh.h"

#include "pw_unit_test/framework.h"
#include "pw_unit_test/status_macros.h"

#define STR_TO_BYTES(str) (as_bytes(span(str).subspan<0, sizeof(str) - 1>()))

namespace pw::crypto::ecdh {
namespace {

template <typename T>
void ZeroOut(T& container) {
  std::fill(std::begin(container), std::end(container), std::byte{0});
}

Result<P256PublicKey> ExtractPublicKey(const P256Keypair& keypair) {
  std::array<std::byte, kP256CoordSize> x{};
  std::array<std::byte, kP256CoordSize> y{};

  PW_TRY(keypair.GetX(x));
  PW_TRY(keypair.GetY(y));

  return P256PublicKey::Import(x, y);
}

class EcdhP256Test : public ::testing::Test {
 private:
  static bool backend_set_up;

  void SetUp() override {
    if (!backend_set_up) {
      SetUpBackendForTesting();
      backend_set_up = true;
    }
  }

  void TearDown() override {}
};

bool EcdhP256Test::backend_set_up = false;

struct NistTestCase {
  P256ConstCoordinate other_x;
  P256ConstCoordinate other_y;
  P256ConstPrivateKey private_key;
  P256ConstCoordinate x;
  P256ConstCoordinate y;
  P256ConstDhKey expected;
};

// Test cases from NIST:
// https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Algorithm-Validation-Program/documents/components/ecccdhtestvectors.zip
const NistTestCase kNistTestCases[] = {
    {
        STR_TO_BYTES(
            "\x70\x0C\x48\xF7\x7F\x56\x58\x4C\x5C\xC6\x32\xCA\x65\x64\x0D\xB9"
            "\x1B\x6B\xAC\xCE\x3A\x4D\xF6\xB4\x2C\xE7\xCC\x83\x88\x33\xD2\x87"),
        STR_TO_BYTES(
            "\xDB\x71\xE5\x09\xE3\xFD\x9B\x06\x0D\xDB\x20\xBA\x5C\x51\xDC\xC5"
            "\x94\x8D\x46\xFB\xF6\x40\xDF\xE0\x44\x17\x82\xCA\xB8\x5F\xA4\xAC"),
        STR_TO_BYTES(
            "\x7D\x7D\xC5\xF7\x1E\xB2\x9D\xDA\xF8\x0D\x62\x14\x63\x2E\xEA\xE0"
            "\x3D\x90\x58\xAF\x1F\xB6\xD2\x2E\xD8\x0B\xAD\xB6\x2B\xC1\xA5\x34"),
        STR_TO_BYTES(
            "\xEA\xD2\x18\x59\x01\x19\xE8\x87\x6B\x29\x14\x6F\xF8\x9C\xA6\x17"
            "\x70\xC4\xED\xBB\xF9\x7D\x38\xCE\x38\x5E\xD2\x81\xD8\xA6\xB2\x30"),
        STR_TO_BYTES(
            "\x28\xAF\x61\x28\x1F\xD3\x5E\x2F\xA7\x00\x25\x23\xAC\xC8\x5A\x42"
            "\x9C\xB0\x6E\xE6\x64\x83\x25\x38\x9F\x59\xED\xFC\xE1\x40\x51\x41"),
        STR_TO_BYTES(
            "\x46\xFC\x62\x10\x64\x20\xFF\x01\x2E\x54\xA4\x34\xFB\xDD\x2D\x25"
            "\xCC\xC5\x85\x20\x60\x56\x1E\x68\x04\x0D\xD7\x77\x89\x97\xBD\x7B"),
    },
    {
        STR_TO_BYTES(
            "\x80\x9F\x04\x28\x9C\x64\x34\x8C\x01\x51\x5E\xB0\x3D\x5C\xE7\xAC"
            "\x1A\x8C\xB9\x49\x8F\x5C\xAA\x50\x19\x7E\x58\xD4\x3A\x86\xA7\xAE"),
        STR_TO_BYTES(
            "\xB2\x9D\x84\xE8\x11\x19\x7F\x25\xEB\xA8\xF5\x19\x40\x92\xCB\x6F"
            "\xF4\x40\xE2\x6D\x44\x21\x01\x13\x72\x46\x1F\x57\x92\x71\xCD\xA3"),
        STR_TO_BYTES(
            "\x38\xF6\x5D\x6D\xCE\x47\x67\x60\x44\xD5\x8C\xE5\x13\x95\x82\xD5"
            "\x68\xF6\x4B\xB1\x60\x98\xD1\x79\xDB\xAB\x07\x74\x1D\xD5\xCA\xF5"),
        STR_TO_BYTES(
            "\x11\x9F\x2F\x04\x79\x02\x78\x2A\xB0\xC9\xE2\x7A\x54\xAF\xF5\xEB"
            "\x9B\x96\x48\x29\xCA\x99\xC0\x6B\x02\xDD\xBA\x95\xB0\xA3\xF6\xD0"),
        STR_TO_BYTES(
            "\x8F\x52\xB7\x26\x66\x4C\xAC\x36\x6F\xC9\x8A\xC7\xA0\x12\xB2\x68"
            "\x2C\xBD\x96\x2E\x5A\xCB\x54\x46\x71\xD4\x1B\x94\x45\x70\x4D\x1D"),
        STR_TO_BYTES(
            "\x05\x7D\x63\x60\x96\xCB\x80\xB6\x7A\x8C\x03\x8C\x89\x0E\x88\x7D"
            "\x1A\xDF\xA4\x19\x5E\x9B\x3C\xE2\x41\xC8\xA7\x78\xC5\x9C\xDA\x67"),
    },
    {
        STR_TO_BYTES(
            "\xA2\x33\x9C\x12\xD4\xA0\x3C\x33\x54\x6D\xE5\x33\x26\x8B\x4A\xD6"
            "\x67\xDE\xBF\x45\x8B\x46\x4D\x77\x44\x36\x36\x44\x0E\xE7\xFE\xC3"),
        STR_TO_BYTES(
            "\xEF\x48\xA3\xAB\x26\xE2\x02\x20\xBC\xDA\x2C\x18\x51\x07\x68\x39"
            "\xDA\xE8\x8E\xAE\x96\x28\x69\xA4\x97\xBF\x73\xCB\x66\xFA\xF5\x36"),
        STR_TO_BYTES(
            "\x1A\xCC\xFA\xF1\xB9\x77\x12\xB8\x5A\x6F\x54\xB1\x48\x98\x5A\x1B"
            "\xDC\x4C\x9B\xEC\x0B\xD2\x58\xCA\xD4\xB3\xD6\x03\xF4\x9F\x32\xC8"),
        STR_TO_BYTES(
            "\xD9\xF2\xB7\x9C\x17\x28\x45\xBF\xDB\x56\x0B\xBB\x01\x44\x7C\xA5"
            "\xEC\xC0\x47\x0A\x09\x51\x3B\x61\x26\x90\x2C\x6B\x4F\x8D\x10\x51"),
        STR_TO_BYTES(
            "\xF8\x15\xEF\x5E\xC3\x21\x28\xD3\x48\x78\x34\x76\x46\x78\x70\x2E"
            "\x64\xE1\x64\xFF\x73\x15\x18\x5E\x23\xAF\xF5\xFA\xCD\x96\xD7\xBC"),
        STR_TO_BYTES(
            "\x2D\x45\x7B\x78\xB4\x61\x41\x32\x47\x76\x18\xA5\xB0\x77\x96\x5E"
            "\xC9\x07\x30\xA8\xC8\x1A\x1C\x75\xD6\xD4\xEC\x68\x00\x5D\x67\xEC"),
    },
    {
        STR_TO_BYTES(
            "\xDF\x39\x89\xB9\xFA\x55\x49\x57\x19\xB3\xCF\x46\xDC\xCD\x28\xB5"
            "\x15\x3F\x78\x08\x19\x1D\xD5\x18\xEF\xF0\xC3\xCF\xF2\xB7\x05\xED"),
        STR_TO_BYTES(
            "\x42\x22\x94\xFF\x46\x00\x34\x29\xD7\x39\xA3\x32\x06\xC8\x75\x25"
            "\x52\xC8\xBA\x54\xA2\x70\xDE\xFC\x06\xE2\x21\xE0\xFE\xAF\x6A\xC4"),
        STR_TO_BYTES(
            "\x20\x7C\x43\xA7\x9B\xFE\xE0\x3D\xB6\xF4\xB9\x44\xF5\x3D\x2F\xB7"
            "\x6C\xC4\x9E\xF1\xC9\xC4\xD3\x4D\x51\xB6\xC6\x5C\x4D\xB6\x93\x2D"),
        STR_TO_BYTES(
            "\x24\x27\x7C\x33\xF4\x50\x46\x2D\xCB\x3D\x48\x01\xD5\x7B\x9C\xED"
            "\x05\x18\x8F\x16\xC2\x8E\xDA\x87\x32\x58\x04\x8C\xD1\x60\x7E\x0D"),
        STR_TO_BYTES(
            "\xC4\x78\x97\x53\xE2\xB1\xF6\x3B\x32\xFF\x01\x4E\xC4\x2C\xD6\xA6"
            "\x9F\xAC\x81\xDF\xE6\xD0\xD6\xFD\x4A\xF3\x72\xAE\x27\xC4\x6F\x88"),
        STR_TO_BYTES(
            "\x96\x44\x12\x59\x53\x4B\x80\xF6\xAE\xE3\xD2\x87\xA6\xBB\x17\xB5"
            "\x09\x4D\xD4\x27\x7D\x9E\x29\x4F\x8F\xE7\x3E\x48\xBF\x2A\x00\x24"),
    },
    {
        STR_TO_BYTES(
            "\x41\x19\x2D\x28\x13\xE7\x95\x61\xE6\xA1\xD6\xF5\x3C\x8B\xC1\xA4"
            "\x33\xA1\x99\xC8\x35\xE1\x41\xB0\x5A\x74\xA9\x7B\x0F\xAE\xB9\x22"),
        STR_TO_BYTES(
            "\x1A\xF9\x8C\xC4\x5E\x98\xA7\xE0\x41\xB0\x1C\xF3\x5F\x46\x2B\x75"
            "\x62\x28\x13\x51\xC8\xEB\xF3\xFF\xA0\x2E\x33\xA0\x72\x2A\x13\x28"),
        STR_TO_BYTES(
            "\x59\x13\x7E\x38\x15\x23\x50\xB1\x95\xC9\x71\x8D\x39\x67\x3D\x51"
            "\x98\x38\x05\x5A\xD9\x08\xDD\x47\x57\x15\x2F\xD8\x25\x5C\x09\xBF"),
        STR_TO_BYTES(
            "\xA8\xC5\xFD\xCE\x8B\x62\xC5\xAD\xA5\x98\xF1\x41\xAD\xB3\xB2\x6C"
            "\xF2\x54\xC2\x80\xB2\x85\x7A\x63\xD2\xAD\x78\x3A\x73\x11\x5F\x6B"),
        STR_TO_BYTES(
            "\x80\x6E\x1A\xAF\xEC\x4A\xF8\x0A\x0D\x78\x6B\x3D\xE4\x53\x75\xB5"
            "\x17\xA7\xE5\xB5\x1F\xFB\x2C\x35\x65\x37\xC9\xE6\xEF\x22\x7D\x4A"),
        STR_TO_BYTES(
            "\x19\xD4\x4C\x8D\x63\xE8\xE8\xDD\x12\xC2\x2A\x87\xB8\xCD\x4E\xCE"
            "\x27\xAC\xDD\xE0\x4D\xBF\x47\xF7\xF2\x75\x37\xA6\x99\x9A\x8E\x62"),
    },
    {
        STR_TO_BYTES(
            "\x33\xE8\x20\x92\xA0\xF1\xFB\x38\xF5\x64\x9D\x58\x67\xFB\xA2\x8B"
            "\x50\x31\x72\xB7\x03\x55\x74\xBF\x8E\x5B\x71\x00\xA3\x05\x27\x92"),
        STR_TO_BYTES(
            "\xF2\xCF\x6B\x60\x1E\x0A\x05\x94\x5E\x33\x55\x50\xBF\x64\x8D\x78"
            "\x2F\x46\x18\x6C\x77\x2C\x0F\x20\xD3\xCD\x0D\x6B\x8C\xA1\x4B\x2F"),
        STR_TO_BYTES(
            "\xF5\xF8\xE0\x17\x46\x10\xA6\x61\x27\x79\x79\xB5\x8C\xE5\xC9\x0F"
            "\xEE\x6C\x9B\x3B\xB3\x46\xA9\x0A\x71\x96\x25\x5E\x40\xB1\x32\xEF"),
        STR_TO_BYTES(
            "\x7B\x86\x1D\xCD\x28\x44\xA5\xA8\x36\x3F\x6B\x8E\xF8\xD4\x93\x64"
            "\x0F\x55\x87\x92\x17\x18\x9D\x80\x32\x6A\xAD\x94\x80\xDF\xC1\x49"),
        STR_TO_BYTES(
            "\xC4\x67\x5B\x45\xEE\xB3\x06\x40\x5F\x6C\x33\xC3\x8B\xC6\x9E\xB2"
            "\xBD\xEC\x9B\x75\xAD\x5A\xF4\x70\x6A\xAB\x84\x54\x3B\x9C\xC6\x3A"),
        STR_TO_BYTES(
            "\x66\x4E\x45\xD5\xBB\xA4\xAC\x93\x1C\xD6\x5D\x52\x01\x7E\x4B\xE9"
            "\xB1\x9A\x51\x5F\x66\x9B\xEA\x47\x03\x54\x2A\x2C\x52\x5C\xD3\xD3"),
    },
    {
        STR_TO_BYTES(
            "\x6A\x9E\x0C\x3F\x91\x6E\x4E\x31\x5C\x91\x14\x7B\xE5\x71\x68\x6D"
            "\x90\x46\x4E\x8B\xF9\x81\xD3\x4A\x90\xB6\x35\x3B\xCA\x6E\xEB\xA7"),
        STR_TO_BYTES(
            "\x40\xF9\xBE\xAD\x39\xC2\xF2\xBC\xC2\x60\x2F\x75\xB8\xA7\x3E\xC7"
            "\xBD\xFF\xCB\xCE\xAD\x15\x9D\x01\x74\xC6\xC4\xD3\xC5\x35\x7F\x05"),
        STR_TO_BYTES(
            "\x3B\x58\x9A\xF7\xDB\x03\x45\x9C\x23\x06\x8B\x64\xF6\x3F\x28\xD3"
            "\xC3\xC6\xBC\x25\xB5\xBF\x76\xAC\x05\xF3\x54\x82\x88\x8B\x51\x90"),
        STR_TO_BYTES(
            "\x9F\xB3\x8E\x2D\x58\xEA\x1B\xAF\x76\x22\xE9\x67\x20\x10\x1C\xAE"
            "\x3C\xDE\x4B\xA6\xC1\xE9\xFA\x26\xD9\xB1\xDE\x08\x99\x10\x28\x63"),
        STR_TO_BYTES(
            "\xD5\x56\x1B\x90\x04\x06\xED\xF5\x08\x02\xDD\x7D\x73\xE8\x93\x95"
            "\xF8\xAE\xD7\x2F\xBA\x0E\x1D\x1B\x61\xFE\x1D\x22\x30\x22\x60\xF0"),
        STR_TO_BYTES(
            "\xCA\x34\x2D\xAA\x50\xDC\x09\xD6\x1B\xE7\xC1\x96\xC8\x5E\x60\xA8"
            "\x0C\x5C\xB0\x49\x31\x74\x68\x20\xBE\x54\x8C\xDD\xE0\x55\x67\x9D"),
    },
    {
        STR_TO_BYTES(
            "\xA9\xC0\xAC\xAD\xE5\x5C\x2A\x73\xEA\xD1\xA8\x6F\xB0\xA9\x71\x32"
            "\x23\xC8\x24\x75\x79\x1C\xD0\xE2\x10\xB0\x46\x41\x2C\xE2\x24\xBB"),
        STR_TO_BYTES(
            "\xF6\xDE\x0A\xFA\x20\xE9\x3E\x07\x84\x67\xC0\x53\xD2\x41\x90\x3E"
            "\xDA\xD7\x34\xC6\xB4\x03\xBA\x75\x8C\x2B\x5F\xF0\x4C\x9D\x42\x29"),
        STR_TO_BYTES(
            "\xD8\xBF\x92\x9A\x20\xEA\x74\x36\xB2\x46\x1B\x54\x1A\x11\xC8\x0E"
            "\x61\xD8\x26\xC0\xA4\xC9\xD3\x22\xB3\x1D\xD5\x4E\x7F\x58\xB9\xC8"),
        STR_TO_BYTES(
            "\x20\xF0\x76\x31\xE4\xA6\x51\x2A\x89\xAD\x48\x7C\x4E\x9D\x63\x03"
            "\x9E\x57\x9C\xB0\xD7\xA5\x56\xCB\x9E\x66\x1C\xD5\x9C\x1E\x7F\xA4"),
        STR_TO_BYTES(
            "\x6D\xE9\x18\x46\xB3\xEE\xE8\xA5\xEC\x09\xC2\xAB\x1F\x41\xE2\x1B"
            "\xD8\x36\x20\xCC\xDD\x1B\xDC\xE3\xAB\x7E\xA6\xE0\x2D\xD2\x74\xF5"),
        STR_TO_BYTES(
            "\x35\xAA\x9B\x52\x53\x6A\x46\x1B\xFD\xE4\xE8\x5F\xC7\x56\xBE\x92"
            "\x8C\x7D\xE9\x79\x23\xF0\x41\x6C\x7A\x3A\xC8\xF8\x8B\x3D\x44\x89"),
    },
    {
        STR_TO_BYTES(
            "\x94\xE9\x4F\x16\xA9\x82\x55\xFF\xF2\xB9\xAC\x0C\x95\x98\xAA\xC3"
            "\x54\x87\xB3\x23\x2D\x32\x31\xBD\x93\xB7\xDB\x7D\xF3\x6F\x9E\xB9"),
        STR_TO_BYTES(
            "\xD8\x04\x9A\x43\x57\x9C\xFA\x90\xB8\x09\x3A\x94\x41\x6C\xBE\xFB"
            "\xF9\x33\x86\xF1\x5B\x3F\x6E\x19\x0B\x6E\x34\x55\xFE\xDF\xE6\x9A"),
        STR_TO_BYTES(
            "\x0F\x98\x83\xBA\x0E\xF3\x2E\xE7\x5D\xED\x0D\x8B\xDA\x39\xA5\x14"
            "\x6A\x29\xF1\xF2\x50\x7B\x3B\xD4\x58\xDB\xEA\x0B\x2B\xB0\x5B\x4D"),
        STR_TO_BYTES(
            "\xAB\xB6\x1B\x42\x3B\xE5\xD6\xC2\x6E\x21\xC6\x05\x83\x2C\x91\x42"
            "\xDC\x1D\xFE\x5A\x5F\xFF\x28\x72\x67\x37\x93\x6E\x6F\xBF\x51\x6D"),
        STR_TO_BYTES(
            "\x73\x3D\x25\x13\xEF\x58\xBE\xAB\x20\x20\x90\x58\x6F\xAC\x91\xBF"
            "\x0F\xEE\x31\xE8\x0A\xB3\x34\x73\xAB\x23\xA2\xD8\x9E\x58\xFA\xD6"),
        STR_TO_BYTES(
            "\x60\x5C\x16\x17\x8A\x9B\xC8\x75\xDC\xBF\xF5\x4D\x63\xFE\x00\xDF"
            "\x69\x9C\x03\xE8\xA8\x88\xE9\xE9\x4D\xFB\xAB\x90\xB2\x5F\x39\xB4"),
    },
    {
        STR_TO_BYTES(
            "\xE0\x99\xBF\x2A\x4D\x55\x74\x60\xB5\x54\x44\x30\xBB\xF6\xDA\x11"
            "\x00\x4D\x12\x7C\xB5\xD6\x7F\x64\xAB\x07\xC9\x4F\xCD\xF5\x27\x4F"),
        STR_TO_BYTES(
            "\xD9\xC5\x0D\xBE\x70\xD7\x14\xED\xB5\xE2\x21\xF4\xE0\x20\x61\x0E"
            "\xEB\x62\x70\x51\x7E\x68\x8C\xA6\x4F\xB0\xE9\x8C\x7E\xF8\xC1\xC5"),
        STR_TO_BYTES(
            "\x2B\xEE\xDB\x04\xB0\x5C\x69\x88\xF6\xA6\x75\x00\xBB\x81\x3F\xAF"
            "\x2C\xAE\x0D\x58\x0C\x92\x53\xB6\x33\x9E\x4A\x33\x37\xBB\x6C\x08"),
        STR_TO_BYTES(
            "\x3D\x63\xE4\x29\xCB\x5F\xA8\x95\xA9\x24\x71\x29\xBF\x4E\x48\xE8"
            "\x9F\x35\xD7\xB1\x1D\xE8\x15\x8E\xFE\xB3\xE1\x06\xA2\xA8\x73\x95"),
        STR_TO_BYTES(
            "\x0C\xAE\x9E\x47\x7E\xF4\x1E\x7C\x8C\x10\x64\x37\x9B\xB7\xB5\x54"
            "\xDD\xCB\xCA\xE7\x9F\x98\x14\x28\x1F\x1E\x50\xF0\x40\x3C\x61\xF3"),
        STR_TO_BYTES(
            "\xF9\x6E\x40\xA1\xB7\x28\x40\x85\x4B\xB6\x2B\xC1\x3C\x40\xCC\x27"
            "\x95\xE3\x73\xD4\xE7\x15\x98\x0B\x26\x14\x76\x83\x5A\x09\x2E\x0B"),
    },
    {
        STR_TO_BYTES(
            "\xF7\x5A\x5F\xE5\x6B\xDA\x34\xF3\xC1\x39\x62\x96\x62\x6E\xF0\x12"
            "\xDC\x07\xE4\x82\x58\x38\x77\x8A\x64\x5C\x82\x48\xCF\xF0\x16\x58"),
        STR_TO_BYTES(
            "\x33\xBB\xDF\x1B\x17\x72\xD8\x05\x9D\xF5\x68\xB0\x61\xF3\xF1\x12"
            "\x2F\x28\xA8\xD8\x19\x16\x7C\x97\xBE\x44\x8E\x3D\xC3\xFB\x0C\x3C"),
        STR_TO_BYTES(
            "\x77\xC1\x5D\xCF\x44\x61\x0E\x41\x69\x6B\xAB\x75\x89\x43\xEF\xF1"
            "\x40\x93\x33\xE4\xD5\xA1\x1B\xBE\x72\xC8\xF6\xC3\x95\xE9\xF8\x48"),
        STR_TO_BYTES(
            "\xAD\x5D\x13\xC3\xDB\x50\x8D\xDC\xD3\x84\x57\xE5\x99\x14\x34\xA2"
            "\x51\xBE\xD4\x9C\xF5\xDD\xCB\x59\xCD\xEE\x73\x86\x5F\x13\x8C\x9F"),
        STR_TO_BYTES(
            "\x62\xCE\xC1\xE7\x05\x88\xAA\x4F\xDF\xC7\xB9\xA0\x9D\xAA\x67\x80"
            "\x81\xC0\x4E\x12\x08\xB9\xD6\x62\xB8\xA2\x21\x4B\xF8\xE8\x1A\x21"),
        STR_TO_BYTES(
            "\x83\x88\xFA\x79\xC4\xBA\xBD\xCA\x02\xA8\xE8\xA3\x4F\x9E\x43\x55"
            "\x49\x76\xE4\x20\xA4\xAD\x27\x3C\x81\xB2\x6E\x42\x28\xE9\xD3\xA3"),
    },
    {
        STR_TO_BYTES(
            "\x2D\xB4\x54\x0D\x50\x23\x07\x56\x15\x8A\xBF\x61\xD9\x83\x57\x12"
            "\xB6\x48\x6C\x74\x31\x21\x83\xCC\xEF\xCA\xEF\x27\x97\xB7\x67\x4D"),
        STR_TO_BYTES(
            "\x62\xF5\x7F\x31\x4E\x3F\x34\x95\xDC\x4E\x09\x90\x12\xF5\xE0\xBA"
            "\x71\x77\x0F\x96\x60\xA1\xEA\xDA\x54\x10\x4C\xDF\xDE\x77\x24\x3E"),
        STR_TO_BYTES(
            "\x42\xA8\x3B\x98\x50\x11\xD1\x23\x03\xDB\x1A\x80\x0F\x26\x10\xF7"
            "\x4A\xA7\x1C\xDF\x19\xC6\x7D\x54\xCE\x6C\x9E\xD9\x51\xE9\x09\x3E"),
        STR_TO_BYTES(
            "\xAB\x48\xCA\xA6\x1E\xA3\x5F\x13\xF8\xED\x07\xFF\xA6\xA1\x3E\x8D"
            "\xB2\x24\xDF\xEC\xFA\xE1\xA7\xDF\x8B\x1B\xB6\xEB\xAF\x0C\xB9\x7D"),
        STR_TO_BYTES(
            "\x12\x74\x53\x0C\xA2\xC3\x85\xA3\x21\x8B\xDD\xFB\xCB\xF0\xB4\x02"
            "\x4C\x9B\xAD\xD5\x24\x3B\xFF\x83\x4E\xBF\xF2\x4A\x86\x18\xDC\xCB"),
        STR_TO_BYTES(
            "\x72\x87\x7C\xEA\x33\xCC\xC4\x71\x50\x38\xD4\xBC\xBD\xFE\x0E\x43"
            "\xF4\x2A\x9E\x2C\x0C\x3B\x01\x7F\xC2\x37\x0F\x4B\x9A\xCB\xDA\x4A"),
    },
    {
        STR_TO_BYTES(
            "\xCD\x94\xFC\x94\x97\xE8\x99\x07\x50\x30\x9E\x9A\x85\x34\xFD\x11"
            "\x4B\x0A\x6E\x54\xDA\x89\xC4\x79\x61\x01\x89\x70\x41\xD1\x4E\xCB"),
        STR_TO_BYTES(
            "\xC3\xDE\xF4\xB5\xFE\x04\xFA\xEE\x0A\x11\x93\x22\x29\xFF\xF5\x63"
            "\x63\x7B\xFD\xEE\x0E\x79\xC6\xDE\xEA\xF4\x49\xF8\x54\x01\xC5\xC4"),
        STR_TO_BYTES(
            "\xCE\xED\x35\x50\x7B\x5C\x93\xEA\xD5\x98\x91\x19\xB9\xBA\x34\x2C"
            "\xFE\x38\xE6\xE6\x38\xBA\x6E\xEA\x34\x3A\x55\x47\x5D\xE2\x80\x0B"),
        STR_TO_BYTES(
            "\x9A\x8C\xD9\xBD\x72\xE7\x17\x52\xDF\x91\x44\x0F\x77\xC5\x47\x50"
            "\x9A\x84\xDF\x98\x11\x4E\x7D\xE4\xF2\x6C\xDB\x39\x23\x4A\x62\x5D"),
        STR_TO_BYTES(
            "\xD0\x7C\xFC\x84\xC8\xE1\x44\xFA\xB2\x83\x9F\x51\x89\xBB\x1D\x7C"
            "\x88\x63\x1D\x57\x9B\xBC\x58\x01\x2E\xD9\xA2\x32\x7D\xA5\x2F\x62"),
        STR_TO_BYTES(
            "\xE4\xE7\x40\x8D\x85\xFF\x0E\x0E\x9C\x83\x80\x03\xF2\x8C\xDB\xD5"
            "\x24\x7C\xDC\xE3\x1F\x32\xF6\x24\x94\xB7\x0E\x5F\x1B\xC3\x63\x07"),
    },
    {
        STR_TO_BYTES(
            "\x15\xB9\xE4\x67\xAF\x4D\x29\x0C\x41\x74\x02\xE0\x40\x42\x6F\xE4"
            "\xCF\x23\x6B\xAE\x72\xBA\xA3\x92\xED\x89\x78\x0D\xFC\xCD\xB4\x71"),
        STR_TO_BYTES(
            "\xCD\xF4\xE9\x17\x0F\xB9\x04\x30\x2B\x8F\xD9\x3A\x82\x0B\xA8\xCC"
            "\x7E\xD4\xEF\xD3\xA6\xF2\xD6\xB0\x5B\x80\xB2\xFF\x2A\xEE\x4E\x77"),
        STR_TO_BYTES(
            "\x43\xE0\xE9\xD9\x5A\xF4\xDC\x36\x48\x3C\xDD\x19\x68\xD2\xB7\xEE"
            "\xB8\x61\x1F\xCC\xE7\x7F\x3A\x4E\x7D\x05\x9A\xE4\x3E\x50\x96\x04"),
        STR_TO_BYTES(
            "\xF9\x89\xCF\x8E\xE9\x56\xA8\x2E\x7E\xBD\x98\x81\xCD\xBF\xB2\xFD"
            "\x94\x61\x89\xB0\x8D\xB5\x35\x59\xBC\x8C\xFD\xD4\x80\x71\xEB\x14"),
        STR_TO_BYTES(
            "\x5E\xFF\x28\xF1\xA1\x8A\x61\x6B\x04\xB7\xD3\x37\x86\x86\x79\xF6"
            "\xDD\x84\xF9\xA7\xB3\xD7\xB6\xF8\xAF\x27\x6C\x19\x61\x1A\x54\x1D"),
        STR_TO_BYTES(
            "\xED\x56\xBC\xF6\x95\xB7\x34\x14\x2C\x24\xEC\xB1\xFC\x1B\xB6\x4D"
            "\x08\xF1\x75\xEB\x24\x3A\x31\xF3\x7B\x3D\x9B\xB4\x40\x7F\x3B\x96"),
    },
    {
        STR_TO_BYTES(
            "\x49\xC5\x03\xBA\x6C\x4F\xA6\x05\x18\x2E\x18\x6B\x5E\x81\x11\x3F"
            "\x07\x5B\xC1\x1D\xCF\xD5\x1C\x93\x2F\xB2\x1E\x95\x1E\xEE\x2F\xA1"),
        STR_TO_BYTES(
            "\x8A\xF7\x06\xFF\x09\x22\xD8\x7B\x3F\x0C\x5E\x4E\x31\xD8\xB2\x59"
            "\xAE\xB2\x60\xA9\x26\x96\x43\xED\x52\x0A\x13\xBB\x25\xDA\x59\x24"),
        STR_TO_BYTES(
            "\xB2\xF3\x60\x0D\xF3\x36\x8E\xF8\xA0\xBB\x85\xAB\x22\xF4\x1F\xC0"
            "\xE5\xF4\xFD\xD5\x4B\xE8\x16\x7A\x5C\x3C\xD4\xB0\x8D\xB0\x49\x03"),
        STR_TO_BYTES(
            "\x69\xC6\x27\x62\x5B\x36\xA4\x29\xC3\x98\xB4\x5C\x38\x67\x7C\xB3"
            "\x5D\x8B\xEB\x1C\xF7\x8A\x57\x1E\x40\xE9\x9F\xE4\xEA\xC1\xCD\x4E"),
        STR_TO_BYTES(
            "\x81\x69\x01\x12\xB0\xA8\x8F\x20\xF7\x13\x6B\x28\xD7\xD4\x7E\x5F"
            "\xBC\x2A\xDA\x3C\x8E\xDD\x87\x58\x9B\xC1\x9E\xC9\x59\x06\x37\xBD"),
        STR_TO_BYTES(
            "\xBC\x5C\x70\x55\x08\x9F\xC9\xD6\xC8\x9F\x83\xC1\xEA\x1A\xDA\x87"
            "\x9D\x99\x34\xB2\xEA\x28\xFC\xF4\xE4\xA7\xE9\x84\xB2\x8A\xD2\xCF"),
    },
    {
        STR_TO_BYTES(
            "\x19\xB3\x8D\xE3\x9F\xDD\x2F\x70\xF7\x09\x16\x31\xA4\xF7\x5D\x19"
            "\x93\x74\x0B\xA9\x42\x91\x62\xC2\xA4\x53\x12\x40\x16\x36\xB2\x9C"),
        STR_TO_BYTES(
            "\x09\xAE\xD7\x23\x2B\x28\xE0\x60\x94\x17\x41\xB6\x82\x8B\xCD\xFA"
            "\x2B\xC4\x9C\xC8\x44\xF3\x77\x36\x11\x50\x4F\x82\xA3\x90\xA5\xAE"),
        STR_TO_BYTES(
            "\x40\x02\x53\x43\x07\xF8\xB6\x2A\x9B\xF6\x7F\xF6\x41\xDD\xC6\x0F"
            "\xEF\x59\x3B\x17\xC3\x34\x12\x39\xE9\x5B\xDB\x3E\x57\x9B\xFD\xC8"),
        STR_TO_BYTES(
            "\x5F\xE9\x64\x67\x13\x15\xA1\x8A\xA6\x8A\x2A\x6E\x3D\xD1\xFD\xE7"
            "\xE2\x3B\x8C\xE7\x18\x14\x71\xCF\xAC\x43\xC9\x9E\x1A\xE8\x02\x62"),
        STR_TO_BYTES(
            "\xD5\x82\x7B\xE2\x82\xE6\x2C\x84\xDE\x53\x1B\x96\x38\x84\xBA\x83"
            "\x2D\xB5\xD6\xB2\xC3\xA2\x56\xF0\xE6\x04\xFE\x7E\x6B\x8A\x7F\x72"),
        STR_TO_BYTES(
            "\x9A\x4E\x8E\x65\x7F\x6B\x0E\x09\x7F\x47\x95\x4A\x63\xC7\x5D\x74"
            "\xFC\xBA\x71\xA3\x0D\x83\x65\x1E\x3E\x5A\x91\xAA\x7C\xCD\x83\x43"),
    },
    {
        STR_TO_BYTES(
            "\x2C\x91\xC6\x1F\x33\xAD\xFE\x93\x11\xC9\x42\xFD\xBF\xF6\xBA\x47"
            "\x02\x0F\xEF\xF4\x16\xB7\xBB\x63\xCE\xC1\x3F\xAF\x9B\x09\x99\x54"),
        STR_TO_BYTES(
            "\x6C\xAB\x31\xB0\x64\x19\xE5\x22\x1F\xCA\x01\x4F\xB8\x4E\xC8\x70"
            "\x62\x2A\x1B\x12\xBA\xB5\xAE\x43\x68\x2A\xA7\xEA\x73\xEA\x08\xD0"),
        STR_TO_BYTES(
            "\x4D\xFA\x12\xDE\xFC\x60\x31\x90\x21\xB6\x81\xB3\xFF\x84\xA1\x0A"
            "\x51\x19\x58\xC8\x50\x93\x9E\xD4\x56\x35\x93\x4B\xA4\x97\x91\x47"),
        STR_TO_BYTES(
            "\xC9\xB2\xB8\x49\x6F\x14\x40\xBD\x4A\x2D\x1E\x52\x75\x2F\xD3\x72"
            "\x83\x5B\x36\x48\x85\xE1\x54\xA7\xDA\xC4\x92\x95\xF2\x81\xEC\x7C"),
        STR_TO_BYTES(
            "\xFB\xE6\xB9\x26\xA8\xA4\xDE\x26\xCC\xC8\x3B\x80\x2B\x12\x12\x40"
            "\x07\x54\xBE\x25\xD9\xF3\xEE\xAF\x00\x8B\x09\x87\x0A\xE7\x63\x21"),
        STR_TO_BYTES(
            "\x3C\xA1\xFC\x7A\xD8\x58\xFB\x1A\x6A\xBA\x23\x25\x42\xF3\xE2\xA7"
            "\x49\xFF\xC7\x20\x3A\x23\x74\xA3\xF3\xD3\x26\x7F\x1F\xC9\x7B\x78"),
    },
    {
        STR_TO_BYTES(
            "\xA2\x8A\x2E\xDF\x58\x02\x56\x68\xF7\x24\xAA\xF8\x3A\x50\x95\x6B"
            "\x7A\xC1\xCF\xBB\xFF\x79\xB0\x8C\x3B\xF8\x7D\xFD\x28\x28\xD7\x67"),
        STR_TO_BYTES(
            "\xDF\xA7\xBF\xFF\xD4\xC7\x66\xB8\x6A\xBE\xAF\x5C\x99\xB6\xE5\x0C"
            "\xB9\xCC\xC9\xD9\xD0\x0B\x7F\xFC\x78\x04\xB0\x49\x1B\x67\xBC\x03"),
        STR_TO_BYTES(
            "\x13\x31\xF6\xD8\x74\xA4\xED\x3B\xC4\xA2\xC6\xE9\xC7\x43\x31\xD3"
            "\x03\x97\x96\x31\x4B\xEE\xE3\xB7\x15\x2F\xCD\xBA\x55\x56\x30\x4E"),
        STR_TO_BYTES(
            "\x59\xE1\xE1\x01\x52\x10\x46\xAD\x9C\xF1\xD0\x82\xE9\xD2\xEC\x7D"
            "\xD2\x25\x30\xCC\xE0\x64\x99\x1F\x1E\x55\xC5\xBC\xF5\xFC\xB5\x91"),
        STR_TO_BYTES(
            "\x48\x2F\x4F\x67\x31\x76\xC8\xFD\xAA\x0B\xB6\xE5\x9B\x15\xA3\xE4"
            "\x74\x54\xE3\xA0\x42\x97\xD3\x86\x3C\x93\x38\xD9\x8A\xDD\x1F\x37"),
        STR_TO_BYTES(
            "\x1A\xAA\xBE\x7E\xE6\xE4\xA6\xFA\x73\x22\x91\x20\x24\x33\xA2\x37"
            "\xDF\x1B\x49\xBC\x53\x86\x6B\xFB\xE0\x0D\xB9\x6A\x0F\x58\x22\x4F"),
    },
    {
        STR_TO_BYTES(
            "\xA2\xEF\x85\x7A\x08\x1F\x9D\x6E\xB2\x06\xA8\x1C\x4C\xF7\x8A\x80"
            "\x2B\xDF\x59\x8A\xE3\x80\xC8\x88\x6E\xCD\x85\xFD\xC1\xED\x76\x44"),
        STR_TO_BYTES(
            "\x56\x3C\x4C\x20\x41\x9F\x07\xBC\x17\xD0\x53\x9F\xAD\xE1\x85\x5E"
            "\x34\x83\x95\x15\xB8\x92\xC0\xF5\xD2\x65\x61\xF9\x7F\xA0\x4D\x1A"),
        STR_TO_BYTES(
            "\xDD\x5E\x9F\x70\xAE\x74\x00\x73\xCA\x02\x04\xDF\x60\x76\x3F\xB6"
            "\x03\x6C\x45\x70\x9B\xF4\xA7\xBB\x4E\x67\x14\x12\xFA\xD6\x5D\xA3"),
        STR_TO_BYTES(
            "\x30\xB9\xDB\x2E\x2E\x97\x7B\xCD\xC9\x8C\xB8\x7D\xD7\x36\xCB\xD8"
            "\xE7\x85\x52\x12\x19\x25\xCF\x16\xE1\x93\x36\x57\xC2\xFB\x23\x14"),
        STR_TO_BYTES(
            "\x6A\x45\x02\x88\x00\xB8\x12\x91\xBC\xE5\xC2\xE1\xFE\xD7\xDE\xD6"
            "\x50\x62\x0E\xBB\xE6\x05\x0C\x6F\x3A\x7F\x0D\xFB\x46\x73\xAB\x5C"),
        STR_TO_BYTES(
            "\x43\x0E\x6A\x4F\xBA\x44\x49\xD7\x00\xD2\x73\x3E\x55\x7F\x66\xA3"
            "\xBF\x3D\x50\x51\x7C\x12\x71\xB1\xDD\xAE\x11\x61\xB7\xAC\x79\x8C"),
    },
    {
        STR_TO_BYTES(
            "\xCC\xD8\xA2\xD8\x6B\xC9\x2F\x2E\x01\xBC\xE4\xD6\x92\x2C\xF7\xFE"
            "\x16\x26\xAE\xD0\x44\x68\x5E\x95\xE2\xEE\xBD\x46\x45\x05\xF0\x1F"),
        STR_TO_BYTES(
            "\xE9\xDD\xD5\x83\xA9\x63\x5A\x66\x77\x77\xD5\xB8\xA8\xF3\x1B\x0F"
            "\x79\xEB\xA1\x2C\x75\x02\x34\x10\xB5\x4B\x85\x67\xDD\xDC\x0F\x38"),
        STR_TO_BYTES(
            "\x5A\xE0\x26\xCF\xC0\x60\xD5\x56\x00\x71\x7E\x55\xB8\xA1\x2E\x11"
            "\x6D\x1D\x0D\xF3\x4A\xF8\x31\x97\x90\x57\x60\x7C\x2D\x9C\x2F\x76"),
        STR_TO_BYTES(
            "\x46\xC9\xEB\xD1\xA4\xA3\xC8\xC0\xB6\xD5\x72\xB5\xDC\xFB\xA1\x24"
            "\x67\x60\x32\x08\xA9\xCB\x5D\x2A\xCF\xBB\x73\x3C\x40\xCF\x63\x91"),
        STR_TO_BYTES(
            "\x46\xC9\x13\xA2\x7D\x04\x41\x85\xD3\x8B\x46\x7A\xCE\x01\x1E\x04"
            "\xD4\xD9\xBB\xBB\x8C\xB9\xAE\x25\xFA\x92\xAA\xF1\x5A\x59\x5E\x86"),
        STR_TO_BYTES(
            "\x1C\xE9\xE6\x74\x05\x29\x49\x9F\x98\xD1\xF1\xD7\x13\x29\x14\x7A"
            "\x33\xDF\x1D\x05\xE4\x76\x5B\x53\x9B\x11\xCF\x61\x5D\x69\x74\xD3"),
    },
    {
        STR_TO_BYTES(
            "\xC1\x88\xFF\xC8\x94\x7F\x73\x01\xFB\x7B\x53\xE3\x67\x46\x09\x7C"
            "\x21\x34\xBF\x9C\xC9\x81\xBA\x74\xB4\xE9\xC4\x36\x1F\x59\x5E\x4E"),
        STR_TO_BYTES(
            "\xBF\x7D\x2F\x20\x56\xE7\x24\x21\xEF\x39\x3F\x0C\x0F\x2B\x0E\x00"
            "\x13\x0E\x3C\xAC\x4A\xBB\xCC\x00\x28\x61\x68\xE8\x5E\xC5\x50\x51"),
        STR_TO_BYTES(
            "\xB6\x01\xAC\x42\x5D\x5D\xBF\x9E\x17\x35\xC5\xE2\xD5\xBD\xB7\x9C"
            "\xA9\x8B\x3D\x5B\xE4\xA2\xCF\xD6\xF2\x27\x3F\x15\x0E\x06\x4D\x9D"),
        STR_TO_BYTES(
            "\x7C\x9E\x95\x08\x41\xD2\x6C\x8D\xDE\x89\x94\x39\x8B\x8F\x5D\x47"
            "\x5A\x02\x2B\xC6\x3D\xE7\x77\x3F\xCF\x8D\x55\x2E\x01\xF1\xBA\x0A"),
        STR_TO_BYTES(
            "\xCC\x42\xB9\x88\x5C\x9B\x3B\xEE\x0F\x8D\x8C\x57\xD3\xA8\xF6\x35"
            "\x50\x16\xC0\x19\xC4\x06\x2F\xA2\x2C\xFF\x2F\x20\x9B\x5C\xC2\xE1"),
        STR_TO_BYTES(
            "\x46\x90\xE3\x74\x3C\x07\xD6\x43\xF1\xBC\x18\x36\x36\xAB\x2A\x9C"
            "\xB9\x36\xA6\x0A\x80\x21\x13\xC4\x9B\xB1\xB3\xF2\xD0\x66\x16\x60"),
    },
    {
        STR_TO_BYTES(
            "\x31\x7E\x10\x20\xFF\x53\xFC\xCE\xF1\x8B\xF4\x7B\xB7\xF2\xDD\x77"
            "\x07\xFB\x7B\x7A\x75\x78\xE0\x4F\x35\xB3\xBE\xED\x22\x2A\x0E\xB6"),
        STR_TO_BYTES(
            "\x09\x42\x0C\xE5\xA1\x9D\x77\xC6\xFE\x1E\xE5\x87\xE6\xA4\x9F\xBA"
            "\xF8\xF2\x80\xE8\xDF\x03\x3D\x75\x40\x33\x02\xE5\xA2\x7D\xB2\xAE"),
        STR_TO_BYTES(
            "\xFE\xFB\x1D\xDA\x18\x45\x31\x2B\x5F\xCE\x6B\x81\xB2\xBE\x20\x5A"
            "\xF2\xF3\xA2\x74\xF5\xA2\x12\xF6\x6C\x0D\x9F\xC3\x3D\x7A\xE5\x35"),
        STR_TO_BYTES(
            "\x38\xB5\x4D\xB8\x55\x00\xCB\x20\xC6\x10\x56\xED\xD3\xD8\x8B\x6A"
            "\x9D\xC2\x67\x80\xA0\x47\xF2\x13\xA6\xE1\xB9\x00\xF7\x65\x96\xEB"),
        STR_TO_BYTES(
            "\x63\x87\xE4\xE5\x78\x15\x71\xE4\xEB\x8A\xE6\x29\x91\xA3\x3B\x5D"
            "\xC3\x33\x01\xC5\xBC\x7E\x12\x5D\x53\x79\x4A\x39\x16\x0D\x8F\xD0"),
        STR_TO_BYTES(
            "\x30\xC2\x26\x1B\xD0\x00\x4E\x61\xFE\xDA\x2C\x16\xAA\x5E\x21\xFF"
            "\xA8\xD7\xE7\xF7\xDB\xF6\xEC\x37\x9A\x43\xB4\x8E\x4B\x36\xAE\xB0"),
    },
    {
        STR_TO_BYTES(
            "\x45\xFB\x02\xB2\xCE\xB9\xD7\xC7\x9D\x9C\x2F\xA9\x3E\x9C\x79\x67"
            "\xC2\xFA\x4D\xF5\x78\x9F\x96\x40\xB2\x42\x64\xB1\xE5\x24\xFC\xB1"),
        STR_TO_BYTES(
            "\x5C\x6E\x8E\xCF\x1F\x7D\x30\x23\x89\x3B\x7B\x1C\xA1\xE4\xD1\x78"
            "\x97\x2E\xE2\xA2\x30\x75\x7D\xDC\x56\x4F\xFE\x37\xF5\xC5\xA3\x21"),
        STR_TO_BYTES(
            "\x33\x4A\xE0\xC4\x69\x3D\x23\x93\x5A\x7E\x8E\x04\x3E\xBB\xDE\x21"
            "\xE1\x68\xA7\xCB\xA3\xFA\x50\x7C\x9B\xE4\x1D\x76\x81\xE0\x49\xCE"),
        STR_TO_BYTES(
            "\x3F\x2B\xF1\x58\x9A\xBF\x30\x47\xBF\x3E\x54\xAC\x9A\x95\x37\x9B"
            "\xFF\x95\xF8\xF5\x54\x05\xF6\x4E\xCA\x36\xA7\xEE\xBE\x8F\xFC\xA7"),
        STR_TO_BYTES(
            "\x52\x12\xA9\x4E\x66\xC5\xAE\x9A\x89\x91\x87\x2F\x66\xA7\x27\x23"
            "\xD8\x0E\xC5\xB2\xE9\x25\x74\x5C\x45\x6F\x53\x71\x94\x3B\x3A\x06"),
        STR_TO_BYTES(
            "\x2A\xDA\xE4\xA1\x38\xA2\x39\xDC\xD9\x3C\x24\x3A\x38\x03\xC3\xE4"
            "\xCF\x96\xE3\x7F\xE1\x4E\x6A\x9B\x71\x7B\xE9\x59\x99\x59\xB1\x1C"),
    },
    {
        STR_TO_BYTES(
            "\xA1\x9E\xF7\xBF\xF9\x8A\xDA\x78\x18\x42\xFB\xFC\x51\xA4\x7A\xFF"
            "\x39\xB5\x93\x5A\x1C\x7D\x96\x25\xC8\xD3\x23\xD5\x11\xC9\x2D\xE6"),
        STR_TO_BYTES(
            "\xE9\xC1\x84\xDF\x75\xC9\x55\xE0\x2E\x02\xE4\x00\xFF\xE4\x5F\x78"
            "\xF3\x39\xE1\xAF\xE6\xD0\x56\xFB\x32\x45\xF4\x70\x0C\xE6\x06\xEF"),
        STR_TO_BYTES(
            "\x2C\x4B\xDE\x40\x21\x4F\xCC\x3B\xFC\x47\xD4\xCF\x43\x4B\x62\x9A"
            "\xCB\xE9\x15\x7F\x8F\xD0\x28\x25\x40\x33\x1D\xE7\x94\x2C\xF0\x9D"),
        STR_TO_BYTES(
            "\x29\xC0\x80\x7F\x10\xCB\xC4\x2F\xB4\x5C\x99\x89\xDA\x50\x68\x1E"
            "\xEA\xD7\x16\xDA\xA7\xB9\xE9\x1F\xD3\x2E\x06\x2F\x5E\xB9\x2C\xA0"),
        STR_TO_BYTES(
            "\xFF\x1D\x6D\x19\x55\xD7\x37\x6B\x2D\xA2\x4F\xE1\x16\x3A\x27\x16"
            "\x59\x13\x63\x41\xBC\x2E\xB1\x19\x5F\xC7\x06\xDC\x62\xE7\xF3\x4D"),
        STR_TO_BYTES(
            "\x2E\x27\x7E\xC3\x0F\x5E\xA0\x7D\x6C\xE5\x13\x14\x9B\x94\x79\xB9"
            "\x6E\x07\xF4\xB6\x91\x3B\x1B\x5C\x11\x30\x5C\x14\x44\xA1\xBC\x0B"),
    },
    {
        STR_TO_BYTES(
            "\x35\x6C\x5A\x44\x4C\x04\x9A\x52\xFE\xE0\xAD\xEB\x7E\x5D\x82\xAE"
            "\x5A\xA8\x30\x30\xBF\xFF\x31\xBB\xF8\xCE\x20\x96\xCF\x16\x1C\x4B"),
        STR_TO_BYTES(
            "\x57\xD1\x28\xDE\x8B\x2A\x57\xA0\x94\xD1\xA0\x01\xE5\x72\x17\x3F"
            "\x96\xE8\x86\x6A\xE3\x52\xBF\x29\xCD\xDA\xF9\x2F\xC8\x5B\x2F\x92"),
        STR_TO_BYTES(
            "\x85\xA2\x68\xF9\xD7\x77\x2F\x99\x0C\x36\xB4\x2B\x0A\x33\x1A\xDC"
            "\x92\xB5\x94\x1D\xE0\xB8\x62\xD5\xD8\x9A\x34\x7C\xBF\x8F\xAA\xB0"),
        STR_TO_BYTES(
            "\x9C\xF4\xB9\x85\x81\xCA\x17\x79\x45\x3C\xC8\x16\xFF\x28\xB4\x10"
            "\x0A\xF5\x6C\xF1\xBF\x2E\x5B\xC3\x12\xD8\x3B\x6B\x1B\x21\xD3\x33"),
        STR_TO_BYTES(
            "\x7A\x55\x04\xFC\xAC\x52\x31\xA0\xD1\x2D\x65\x82\x18\x28\x48\x68"
            "\x22\x9C\x84\x4A\x04\xA3\x45\x0D\x6C\x73\x81\xAB\xE0\x80\xBF\x3B"),
        STR_TO_BYTES(
            "\x1E\x51\x37\x3B\xD2\xC6\x04\x4C\x12\x9C\x43\x6E\x74\x2A\x55\xBE"
            "\x2A\x66\x8A\x85\xAE\x08\x44\x1B\x67\x56\x44\x5D\xF5\x49\x38\x57"),
    },
};

TEST_F(EcdhP256Test, NistTestCases) {
  std::array<std::byte, kP256DiffieHellmanKeySize> dh_key_out;

  std::array<std::byte, kP256CoordSize> other_x{};
  std::array<std::byte, kP256CoordSize> other_y{};
  std::array<std::byte, kP256CoordSize> x{};
  std::array<std::byte, kP256CoordSize> y{};

  std::array<std::byte, kP256PrivateKeySize> private_key{};
  std::array<std::byte, kP256DiffieHellmanKeySize> expected{};

  std::array<std::byte, kP256CoordSize> x_buffer{};
  std::array<std::byte, kP256CoordSize> y_buffer{};

  // Big-endian.
  for (const auto& test_case : kNistTestCases) {
    std::memcpy(other_x.data(), test_case.other_x.data(), kP256CoordSize);
    std::memcpy(other_y.data(), test_case.other_y.data(), kP256CoordSize);
    std::memcpy(x.data(), test_case.x.data(), kP256CoordSize);
    std::memcpy(y.data(), test_case.y.data(), kP256CoordSize);
    std::memcpy(
        expected.data(), test_case.expected.data(), kP256DiffieHellmanKeySize);

    PW_TEST_ASSERT_OK_AND_ASSIGN(
        auto pubkey, P256PublicKey::Import(other_x, other_y, endian::big));
    PW_TEST_ASSERT_OK_AND_ASSIGN(auto keypair,
                                 P256Keypair::ImportForTesting(
                                     test_case.private_key, x, y, endian::big));

    ZeroOut(x_buffer);
    ZeroOut(y_buffer);
    PW_TEST_EXPECT_OK(pubkey.GetX(x_buffer, endian::big));
    PW_TEST_EXPECT_OK(pubkey.GetY(y_buffer, endian::big));
    EXPECT_EQ(x_buffer, other_x);
    EXPECT_EQ(y_buffer, other_y);

    ZeroOut(x_buffer);
    ZeroOut(y_buffer);
    PW_TEST_EXPECT_OK(keypair.GetX(x_buffer, endian::big));
    PW_TEST_EXPECT_OK(keypair.GetY(y_buffer, endian::big));
    EXPECT_EQ(x_buffer, x);
    EXPECT_EQ(y_buffer, y);

    PW_TEST_ASSERT_OK(keypair.ComputeDiffieHellman(pubkey, dh_key_out));
    EXPECT_EQ(dh_key_out, expected);
  }

  // Little-endian.
  for (const auto& test_case : kNistTestCases) {
    std::memcpy(other_x.data(), test_case.other_x.data(), kP256CoordSize);
    std::memcpy(other_y.data(), test_case.other_y.data(), kP256CoordSize);
    std::memcpy(
        private_key.data(), test_case.private_key.data(), kP256PrivateKeySize);
    std::memcpy(x.data(), test_case.x.data(), kP256CoordSize);
    std::memcpy(y.data(), test_case.y.data(), kP256CoordSize);

    std::reverse(other_x.begin(), other_x.end());
    std::reverse(other_y.begin(), other_y.end());
    std::reverse(private_key.begin(), private_key.end());
    std::reverse(x.begin(), x.end());
    std::reverse(y.begin(), y.end());

    std::memcpy(
        expected.data(), test_case.expected.data(), kP256DiffieHellmanKeySize);

    PW_TEST_ASSERT_OK_AND_ASSIGN(
        auto pubkey, P256PublicKey::Import(other_x, other_y, endian::little));
    PW_TEST_ASSERT_OK_AND_ASSIGN(
        auto keypair,
        P256Keypair::ImportForTesting(private_key, x, y, endian::little));

    ZeroOut(x_buffer);
    ZeroOut(y_buffer);
    PW_TEST_EXPECT_OK(pubkey.GetX(x_buffer, endian::little));
    PW_TEST_EXPECT_OK(pubkey.GetY(y_buffer, endian::little));
    EXPECT_EQ(x_buffer, other_x);
    EXPECT_EQ(y_buffer, other_y);

    ZeroOut(x_buffer);
    ZeroOut(y_buffer);
    PW_TEST_EXPECT_OK(keypair.GetX(x_buffer, endian::little));
    PW_TEST_EXPECT_OK(keypair.GetY(y_buffer, endian::little));
    EXPECT_EQ(x_buffer, x);
    EXPECT_EQ(y_buffer, y);

    PW_TEST_ASSERT_OK(keypair.ComputeDiffieHellman(pubkey, dh_key_out));
    EXPECT_EQ(dh_key_out, expected);
  }
}

TEST_F(EcdhP256Test, GenerateAndComputeSharedSecret) {
  PW_TEST_ASSERT_OK_AND_ASSIGN(auto keypair_alice, P256Keypair::Generate());
  PW_TEST_ASSERT_OK_AND_ASSIGN(auto keypair_bob, P256Keypair::Generate());

  PW_TEST_ASSERT_OK_AND_ASSIGN(auto pubkey_alice,
                               ExtractPublicKey(keypair_alice));
  PW_TEST_ASSERT_OK_AND_ASSIGN(auto pubkey_bob, ExtractPublicKey(keypair_bob));

  std::array<std::byte, kP256DiffieHellmanKeySize> shared_key_alice;
  std::array<std::byte, kP256DiffieHellmanKeySize> shared_key_bob;

  ZeroOut(shared_key_alice);
  ZeroOut(shared_key_bob);

  PW_TEST_EXPECT_OK(
      keypair_alice.ComputeDiffieHellman(pubkey_bob, shared_key_alice));
  PW_TEST_EXPECT_OK(
      keypair_bob.ComputeDiffieHellman(pubkey_alice, shared_key_bob));

  EXPECT_EQ(shared_key_alice, shared_key_bob);
}

TEST_F(EcdhP256Test, PointNotOnCurveFails) {
  std::array<std::byte, kP256CoordSize> other_x{};
  std::array<std::byte, kP256CoordSize> other_y{};
  std::array<std::byte, kP256CoordSize> x{};
  std::array<std::byte, kP256CoordSize> y{};

  std::array<std::byte, kP256PrivateKeySize> private_key{};

  // Big-endian.
  for (const auto& test_case : kNistTestCases) {
    std::memcpy(other_x.data(), test_case.other_x.data(), kP256CoordSize);
    std::memcpy(other_y.data(), test_case.other_y.data(), kP256CoordSize);
    std::memcpy(x.data(), test_case.x.data(), kP256CoordSize);
    std::memcpy(y.data(), test_case.y.data(), kP256CoordSize);
    std::memcpy(
        private_key.data(), test_case.private_key.data(), kP256CoordSize);

    // Modify the points to no longer be on the curve.
    x[0] = ~x[0];
    other_x[0] = ~x[0];

    EXPECT_FALSE(P256PublicKey::Import(other_x, other_y, endian::big).ok());
    EXPECT_FALSE(
        P256Keypair::ImportForTesting(private_key, x, y, endian::big).ok());

    // Modify local keypair to be valid again, and double check it is valid.
    x[0] = ~x[0];
    PW_TEST_EXPECT_OK(
        P256Keypair::ImportForTesting(private_key, x, y, endian::big));

    // Modify private key to no longer be on the curve.
    ZeroOut(private_key);
    EXPECT_FALSE(
        P256Keypair::ImportForTesting(private_key, x, y, endian::big).ok());
  }

  // Little-endian.
  for (const auto& test_case : kNistTestCases) {
    std::memcpy(other_x.data(), test_case.other_x.data(), kP256CoordSize);
    std::memcpy(other_y.data(), test_case.other_y.data(), kP256CoordSize);
    std::memcpy(x.data(), test_case.x.data(), kP256CoordSize);
    std::memcpy(y.data(), test_case.y.data(), kP256CoordSize);
    std::memcpy(
        private_key.data(), test_case.private_key.data(), kP256PrivateKeySize);

    std::reverse(other_x.begin(), other_x.end());
    std::reverse(other_y.begin(), other_y.end());
    std::reverse(private_key.begin(), private_key.end());
    std::reverse(x.begin(), x.end());
    std::reverse(y.begin(), y.end());

    // Modify the points to no longer be on the curve.
    x[kP256CoordSize - 1] = ~x[kP256CoordSize - 1];
    other_x[kP256CoordSize - 1] = ~other_x[kP256CoordSize - 1];

    EXPECT_FALSE(P256PublicKey::Import(other_x, other_y, endian::big).ok());
    EXPECT_FALSE(
        P256Keypair::ImportForTesting(private_key, x, y, endian::big).ok());

    // Modify local keypair to be valid again, and double check it is valid.
    x[kP256CoordSize - 1] = ~x[kP256CoordSize - 1];
    PW_TEST_EXPECT_OK(
        P256Keypair::ImportForTesting(private_key, x, y, endian::little));

    // Modify private key to be invalid for P256.
    ZeroOut(private_key);
    EXPECT_FALSE(
        P256Keypair::ImportForTesting(private_key, x, y, endian::little).ok());
  }
}

}  // namespace
}  // namespace pw::crypto::ecdh
